#include <stdlib.h>
#include <stdio.h>

struct MemAlloc
{
    const char *file;
    int line;
    int size;
    const void *ptr;
    MemAlloc *next;
};

MemAlloc *head=NULL;

void AddMemAlloc(const void *p, const char *file, int line, int size)
{
    MemAlloc *memAlloc=(MemAlloc*)malloc(sizeof(MemAlloc));

    memAlloc->file=file;
    memAlloc->line=line;
    memAlloc->size=size;
    memAlloc->ptr=p;
    memAlloc->next=head;

    head=memAlloc;
}

void RemoveMemAlloc(const void *p)
{
    MemAlloc *prev=NULL;
    MemAlloc *memAlloc=head;
    
    while(memAlloc)
    {
        if(memAlloc->ptr==p)
        {
            if(memAlloc==head)
            {
                head=memAlloc->next;
            }
            else
            {
                prev->next=memAlloc->next;
            }
            
            free(memAlloc);

            memAlloc=NULL;            
        }
        else
        {
            prev=memAlloc;
            memAlloc=memAlloc->next;
        }
    }
}

void ReportMemLeaks(FILE *stream)
{
    if(head)
    {
        fprintf(stream, "Memory Leaks Detected!\n");
        for(MemAlloc *memAlloc=head; memAlloc; memAlloc=memAlloc->next)
        {
            fprintf(stream, "%d bytes at %s:%d\n", memAlloc->size, memAlloc->file, memAlloc->line);
        }
    }
    else
    {
        fprintf(stream,"No Memory Leaks Detected.\n");
    }
}

void *DebugMalloc(size_t size, const char *file, int line)
{
    void *result=NULL;

    result=malloc(size);

    AddMemAlloc(result, file, line, size);

    return(result);
}

void *DebugCalloc(size_t nmemb, size_t size, const char *file, int line)
{
    void *result=NULL;

    result=calloc(nmemb, size);

    AddMemAlloc(result, file, line, nmemb*size);

    return(result);
}

void DebugFree(void *p)
{
    RemoveMemAlloc(p);

    free(p);
}

void *operator new(size_t size, const char *file, int line)
{ 
    void *result=NULL;

    result=malloc(size);

    AddMemAlloc(result,file,line,size);

    return(result);
}

void operator delete(void *p)
{
    RemoveMemAlloc(p);

    free(p);
}

void operator delete[](void *p)
{
    RemoveMemAlloc(p);

    free(p);
}
